library(tidyverse)
library(fs)
ngsadmix_dir <- "data/ngsadmix_all/maf_0.05" # set NGSadmix outputs directory
N_K <- 10    # set number of K run
N_reps <- 4  # set number of reps run

# pull all log files
log_files <- list.files(ngsadmix_dir, pattern = ".log", full.names = T, recursive=T)

# read in all logs
all_logs <- lapply(1:length(log_files), FUN = function(i) readLines(log_files[i]))

# make list of the line that starts with "best like=" from all logs, just target 'b'
library(stringr)
bestlikes_str_list <- sapply(1:length(log_files), FUN= function(x) all_logs[[x]][which(str_sub(all_logs[[x]], 1, 1) == 'b')])

# make dataframe with 1:N_K and N_reps to add likelihood values
loglikes <- data.frame(K = rep(2:N_K, each=N_reps))

# add the log likelihood (first number in the string)
loglikes$loglike<-as.vector(as.numeric( sub("\\D*(\\d+).*", "\\1", bestlikes_str_list) ))

tapply(loglikes$loglike, loglikes$K, FUN= function(x) mean(abs(x))/sd(abs(x)))
           2            3            4            5            6            7 
1.314224e+03 3.724947e+08          Inf          Inf 5.753390e+02 6.269528e+03 
           8            9           10 
1.961828e+04          Inf          Inf 
alewife_palette <- c("#636c62", "#869ca8", "#a2878a", "#b6bc9f", "#ecc2a3", "#eceeed", "#242b35", "#a39faa", "#ac9b7c", "#3b3a35")

qcolors <- c(`Q1` = "#636c62", 
            `Q2` = "#869ca8", 
            `Q3` = "#a2878a", 
            `Q4` = "#b6bc9f", 
            `Q5` = "#ecc2a3", 
            `Q6` = "#eceeed", 
            `Q7` = "#242b35", 
            `Q8` = "#a39faa", 
            `Q9` = "#ac9b7c", 
            `Q10` = "#3b3a35")

gord <- c("BLUE", 
           "HYBR", 
           "GRTL", 
           "FINL", 
           "MIDL", 
           "CONL", 
           "NATLA", 
           "MIDA")
word <- c("Petitcodiac River", 
           "Hudson River", 
           "Lake Yonah", 
           "Lake Hartwell", 
           "Altamaha River", 
           "Roanoke River", 
           "Lake Superior", 
           "Lake Michigan", 
           "Lake Ontario", 
           "Canandaigua Lake", 
           "Cayuga Lake", 
           "Seneca Lake", 
           "Otisco Lake", 
           "East Grand Lake", 
           "Lake Champlain", 
           "Pattagansett Lake", 
           "Rogers Lake", 
           "Quonnipaug Lake", 
           "Miramichi River", 
           "Saco River", 
           "Black Creek", 
           "Choptank River")

metadata <- read_csv("data/herring_metadata.csv") %>%
  select(NMFS_DNA_ID, 
         GENUS, 
         SPECIES, 
         STATE_F, 
         WATERSHED, 
         WATER_NAME, 
         grouping_v3) %>% 
  mutate(newname = paste0(WATER_NAME, 
                          "-", 
                          NMFS_DNA_ID)) %>%
  mutate(newname = str_replace_all(newname, 
                                   " +", 
                                   "_")) %>%
  mutate(gfact = factor(grouping_v3, 
                        levels = gord), 
         wfact = factor(WATER_NAME, 
                        levels = word)) %>%
  arrange(gfact, wfact)
Rows: 94 Columns: 12── Column specification ──────────────────────────────────────────────────────────
Delimiter: ","
chr (11): sample, NMFS_DNA_ID, BOX_ID, BOX_POSITION, SAMPLE_ID, GENUS, SPECIES...
dbl  (1): BATCH_ID
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
nord <- unique(metadata$newname)

labels <- read_tsv("data/admix-labels.tsv") 
Rows: 23 Columns: 4── Column specification ──────────────────────────────────────────────────────────
Delimiter: "\t"
chr (4): grouping_v3, group_label, WATER_NAME, pop_label
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
tmp <- metadata %>%
  mutate(xpos = 1:n())

group_pos <- tmp %>%
  group_by(grouping_v3) %>%
  summarise(midx = (min(xpos) - 0.5 + max(xpos) + 0.5)/ 2, 
            linex = max(xpos) + 0.5) %>%
  mutate(midy = 1)

group_labels <- group_pos %>%
  left_join(labels %>% group_by(grouping_v3) %>% slice(1)) %>%
  mutate(gfact = factor(grouping_v3, 
                        levels = gord)) %>%
  arrange(gfact)
Joining with `by = join_by(grouping_v3)`
pop_pos <- tmp %>%
  group_by(grouping_v3, WATER_NAME) %>%
  summarise(midx = (min(xpos) - 0.5 + max(xpos) + 0.5) / 2, 
            linex = max(xpos) + 0.5) %>%
  mutate(midy = 0)
`summarise()` has grouped output by 'grouping_v3'. You can override using the `.groups` argument.
pop_labels <- pop_pos %>%
  left_join(labels)
Joining with `by = join_by(grouping_v3, WATER_NAME)`
ngsadmix_files <- dir_ls("data/ngsadmix_all", 
                         recurse = TRUE, 
                         glob = "*.qopt_with_sample_names")

ngsAdmix_tib <- lapply(ngsadmix_files, function(x) {
  read.table(x, 
             header = TRUE) %>%
    pivot_longer(cols = -sample, 
                 names_to = "Qval", 
                 values_to = "value") %>%
    mutate(path = x, 
           .before = sample)
}) %>%
  bind_rows() %>%
  filter(!is.na(value)) %>%
  mutate(Qval = str_replace(Qval, 
                            "X", 
                            "Q")) %>%
  extract(path, 
          into = c("K", 
                   "rep"), 
          regex = ".*K_([0-9]+)_rep_([0-9]+)/.*$", 
          convert = TRUE) %>%
  inner_join(., 
             metadata, 
             by = c("sample" = "NMFS_DNA_ID"), 
             relationship = "many-to-many") %>%
  mutate(gfact = factor(grouping_v3, 
                        levels = gord), 
         wfact = factor(WATER_NAME, 
                        levels = word)) %>%
  arrange(gfact, wfact)
ggplot(ngsAdmix_tib) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

K2 <- ngsAdmix_tib %>%
  filter(K == 2)

K3 <- ngsAdmix_tib %>%
  filter(K == 3)

K4 <- ngsAdmix_tib %>%
  filter(K == 4)

K5 <- ngsAdmix_tib %>%
  filter(K == 5)

K6 <- ngsAdmix_tib %>%
  filter(K == 6)

K7 <- ngsAdmix_tib %>%
  filter(K == 7)

K8 <- ngsAdmix_tib %>%
  filter(K == 8)

K9 <- ngsAdmix_tib %>%
  filter(K == 9)

K10 <- ngsAdmix_tib %>%
  filter(K == 10)
ggplot(K2) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

In the admixture scenario of 2 source populations, the samples split into the two species of blueback (left) and alewife (right).

ggplot(K3) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

In the admixture scenario of 3 source populations, the Great and Finger Lakes samples pull out into their own group.

ggplot(K4) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

In the admixture scenario of four source populations, we see the the Roanoke River, East Grand Lake, and Lake Champlain samples pull out into their own group.

ggplot(K5) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

In the most admixture scenarios of five source populations, we begin to see Great and Finger Lakes form a nonspecific mosaic except for in the third repetition in which the Connecticut Lakes samples break out into their own group.

ggplot(K6) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

In the an admixture scenario of six source populations, we see the Connecticut Lakes samples break out and the same random mosaic in the Great and Finger Lakes samples, except for in the third repetition where only Pattagansett and Rogers Lakes separate out into their own source population.

ggplot(K7) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

In an admixture scenario of seven source populations, the anadromous alewife show their own source population.

ggplot(K8) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

In an admixture scenario of eight source populations, blueback samples begin to mosaic as well as the anadromous samples with the Quonnipaug Lake samples breaking out with the source population more present in the Mid-Atlantic managing unit.

ggplot(K9) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

In an admixture scenario of nine source populations, all blueback samples come from the same source population, three source populations mosaic through the Great and Finger Lakes, Rogers Lake breaks out into their own source population, and the anadromous samples mosaic into two nonspecific source populations.

ggplot(K10) +
  geom_col(mapping = aes(x = factor(newname, 
                                    levels = nord), 
                         y = value, 
                         fill = Qval)) +
  scale_fill_manual(values = qcolors) + 
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, 
                                   size = 8, 
                                   vjust = 0.5)) +
  facet_grid(rep ~ K) +
  labs(x = "", 
       y = "Q value") +
  geom_vline(xintercept = pop_labels$linex, 
             linetype = 2, 
             color = "gray25") +
  geom_vline(xintercept = group_labels$linex)

In an admixture scenario of ten source populations, 1-2 Lake Champlain samples break out with Roanoke River samples, with all other Lake Champlain and East Grand Lake samples in their own source population. Pattagansett Lake breaks out from the other Connecticut Lakes samples.

LS0tCnRpdGxlOiAiQWRtaXh0dXJlIFByb3BvcnRpb25zIgpzdWJ0aXRsZTogIkFsbCBTYW1wbGVzIgphdXRob3I6ICJIYW5hIEsuIE1veWxlIgpkYXRlOiAiMjAyNCBKdWx5IDMwIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBsaWJyYXJpZXN9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGZzKQpgYGAKCmBgYHtyIGxvZ19saWtlbGlob29kc30KbmdzYWRtaXhfZGlyIDwtICJkYXRhL25nc2FkbWl4X2FsbC9tYWZfMC4wNSIgIyBzZXQgTkdTYWRtaXggb3V0cHV0cyBkaXJlY3RvcnkKTl9LIDwtIDEwICAgICMgc2V0IG51bWJlciBvZiBLIHJ1bgpOX3JlcHMgPC0gNCAgIyBzZXQgbnVtYmVyIG9mIHJlcHMgcnVuCgojIHB1bGwgYWxsIGxvZyBmaWxlcwpsb2dfZmlsZXMgPC0gbGlzdC5maWxlcyhuZ3NhZG1peF9kaXIsIHBhdHRlcm4gPSAiLmxvZyIsIGZ1bGwubmFtZXMgPSBULCByZWN1cnNpdmU9VCkKCiMgcmVhZCBpbiBhbGwgbG9ncwphbGxfbG9ncyA8LSBsYXBwbHkoMTpsZW5ndGgobG9nX2ZpbGVzKSwgRlVOID0gZnVuY3Rpb24oaSkgcmVhZExpbmVzKGxvZ19maWxlc1tpXSkpCgojIG1ha2UgbGlzdCBvZiB0aGUgbGluZSB0aGF0IHN0YXJ0cyB3aXRoICJiZXN0IGxpa2U9IiBmcm9tIGFsbCBsb2dzLCBqdXN0IHRhcmdldCAnYicKbGlicmFyeShzdHJpbmdyKQpiZXN0bGlrZXNfc3RyX2xpc3QgPC0gc2FwcGx5KDE6bGVuZ3RoKGxvZ19maWxlcyksIEZVTj0gZnVuY3Rpb24oeCkgYWxsX2xvZ3NbW3hdXVt3aGljaChzdHJfc3ViKGFsbF9sb2dzW1t4XV0sIDEsIDEpID09ICdiJyldKQoKIyBtYWtlIGRhdGFmcmFtZSB3aXRoIDE6Tl9LIGFuZCBOX3JlcHMgdG8gYWRkIGxpa2VsaWhvb2QgdmFsdWVzCmxvZ2xpa2VzIDwtIGRhdGEuZnJhbWUoSyA9IHJlcCgyOk5fSywgZWFjaD1OX3JlcHMpKQoKIyBhZGQgdGhlIGxvZyBsaWtlbGlob29kIChmaXJzdCBudW1iZXIgaW4gdGhlIHN0cmluZykKbG9nbGlrZXMkbG9nbGlrZTwtYXMudmVjdG9yKGFzLm51bWVyaWMoIHN1YigiXFxEKihcXGQrKS4qIiwgIlxcMSIsIGJlc3RsaWtlc19zdHJfbGlzdCkgKSkKCnRhcHBseShsb2dsaWtlcyRsb2dsaWtlLCBsb2dsaWtlcyRLLCBGVU49IGZ1bmN0aW9uKHgpIG1lYW4oYWJzKHgpKS9zZChhYnMoeCkpKQpgYGAKCmBgYHtyIGRhdGFfb3JnfQphbGV3aWZlX3BhbGV0dGUgPC0gYygiIzYzNmM2MiIsICIjODY5Y2E4IiwgIiNhMjg3OGEiLCAiI2I2YmM5ZiIsICIjZWNjMmEzIiwgIiNlY2VlZWQiLCAiIzI0MmIzNSIsICIjYTM5ZmFhIiwgIiNhYzliN2MiLCAiIzNiM2EzNSIpCgpxY29sb3JzIDwtIGMoYFExYCA9ICIjNjM2YzYyIiwgCiAgICAgICAgICAgIGBRMmAgPSAiIzg2OWNhOCIsIAogICAgICAgICAgICBgUTNgID0gIiNhMjg3OGEiLCAKICAgICAgICAgICAgYFE0YCA9ICIjYjZiYzlmIiwgCiAgICAgICAgICAgIGBRNWAgPSAiI2VjYzJhMyIsIAogICAgICAgICAgICBgUTZgID0gIiNlY2VlZWQiLCAKICAgICAgICAgICAgYFE3YCA9ICIjMjQyYjM1IiwgCiAgICAgICAgICAgIGBROGAgPSAiI2EzOWZhYSIsIAogICAgICAgICAgICBgUTlgID0gIiNhYzliN2MiLCAKICAgICAgICAgICAgYFExMGAgPSAiIzNiM2EzNSIpCgpnb3JkIDwtIGMoIkJMVUUiLCAKICAgICAgICAgICAiSFlCUiIsIAogICAgICAgICAgICJHUlRMIiwgCiAgICAgICAgICAgIkZJTkwiLCAKICAgICAgICAgICAiTUlETCIsIAogICAgICAgICAgICJDT05MIiwgCiAgICAgICAgICAgIk5BVExBIiwgCiAgICAgICAgICAgIk1JREEiKQp3b3JkIDwtIGMoIlBldGl0Y29kaWFjIFJpdmVyIiwgCiAgICAgICAgICAgIkh1ZHNvbiBSaXZlciIsIAogICAgICAgICAgICJMYWtlIFlvbmFoIiwgCiAgICAgICAgICAgIkxha2UgSGFydHdlbGwiLCAKICAgICAgICAgICAiQWx0YW1haGEgUml2ZXIiLCAKICAgICAgICAgICAiUm9hbm9rZSBSaXZlciIsIAogICAgICAgICAgICJMYWtlIFN1cGVyaW9yIiwgCiAgICAgICAgICAgIkxha2UgTWljaGlnYW4iLCAKICAgICAgICAgICAiTGFrZSBPbnRhcmlvIiwgCiAgICAgICAgICAgIkNhbmFuZGFpZ3VhIExha2UiLCAKICAgICAgICAgICAiQ2F5dWdhIExha2UiLCAKICAgICAgICAgICAiU2VuZWNhIExha2UiLCAKICAgICAgICAgICAiT3Rpc2NvIExha2UiLCAKICAgICAgICAgICAiRWFzdCBHcmFuZCBMYWtlIiwgCiAgICAgICAgICAgIkxha2UgQ2hhbXBsYWluIiwgCiAgICAgICAgICAgIlBhdHRhZ2Fuc2V0dCBMYWtlIiwgCiAgICAgICAgICAgIlJvZ2VycyBMYWtlIiwgCiAgICAgICAgICAgIlF1b25uaXBhdWcgTGFrZSIsIAogICAgICAgICAgICJNaXJhbWljaGkgUml2ZXIiLCAKICAgICAgICAgICAiU2FjbyBSaXZlciIsIAogICAgICAgICAgICJCbGFjayBDcmVlayIsIAogICAgICAgICAgICJDaG9wdGFuayBSaXZlciIpCgptZXRhZGF0YSA8LSByZWFkX2NzdigiZGF0YS9oZXJyaW5nX21ldGFkYXRhLmNzdiIpICU+JQogIHNlbGVjdChOTUZTX0ROQV9JRCwgCiAgICAgICAgIEdFTlVTLCAKICAgICAgICAgU1BFQ0lFUywgCiAgICAgICAgIFNUQVRFX0YsIAogICAgICAgICBXQVRFUlNIRUQsIAogICAgICAgICBXQVRFUl9OQU1FLCAKICAgICAgICAgZ3JvdXBpbmdfdjMpICU+JSAKICBtdXRhdGUobmV3bmFtZSA9IHBhc3RlMChXQVRFUl9OQU1FLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAiLSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIE5NRlNfRE5BX0lEKSkgJT4lCiAgbXV0YXRlKG5ld25hbWUgPSBzdHJfcmVwbGFjZV9hbGwobmV3bmFtZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiArIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl8iKSkgJT4lCiAgbXV0YXRlKGdmYWN0ID0gZmFjdG9yKGdyb3VwaW5nX3YzLCAKICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gZ29yZCksIAogICAgICAgICB3ZmFjdCA9IGZhY3RvcihXQVRFUl9OQU1FLCAKICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gd29yZCkpICU+JQogIGFycmFuZ2UoZ2ZhY3QsIHdmYWN0KQoKbm9yZCA8LSB1bmlxdWUobWV0YWRhdGEkbmV3bmFtZSkKCmxhYmVscyA8LSByZWFkX3RzdigiZGF0YS9hZG1peC1sYWJlbHMudHN2IikgCgp0bXAgPC0gbWV0YWRhdGEgJT4lCiAgbXV0YXRlKHhwb3MgPSAxOm4oKSkKCmdyb3VwX3BvcyA8LSB0bXAgJT4lCiAgZ3JvdXBfYnkoZ3JvdXBpbmdfdjMpICU+JQogIHN1bW1hcmlzZShtaWR4ID0gKG1pbih4cG9zKSAtIDAuNSArIG1heCh4cG9zKSArIDAuNSkvIDIsIAogICAgICAgICAgICBsaW5leCA9IG1heCh4cG9zKSArIDAuNSkgJT4lCiAgbXV0YXRlKG1pZHkgPSAxKQoKZ3JvdXBfbGFiZWxzIDwtIGdyb3VwX3BvcyAlPiUKICBsZWZ0X2pvaW4obGFiZWxzICU+JSBncm91cF9ieShncm91cGluZ192MykgJT4lIHNsaWNlKDEpKSAlPiUKICBtdXRhdGUoZ2ZhY3QgPSBmYWN0b3IoZ3JvdXBpbmdfdjMsIAogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBnb3JkKSkgJT4lCiAgYXJyYW5nZShnZmFjdCkKCnBvcF9wb3MgPC0gdG1wICU+JQogIGdyb3VwX2J5KGdyb3VwaW5nX3YzLCBXQVRFUl9OQU1FKSAlPiUKICBzdW1tYXJpc2UobWlkeCA9IChtaW4oeHBvcykgLSAwLjUgKyBtYXgoeHBvcykgKyAwLjUpIC8gMiwgCiAgICAgICAgICAgIGxpbmV4ID0gbWF4KHhwb3MpICsgMC41KSAlPiUKICBtdXRhdGUobWlkeSA9IDApCgpwb3BfbGFiZWxzIDwtIHBvcF9wb3MgJT4lCiAgbGVmdF9qb2luKGxhYmVscykKCm5nc2FkbWl4X2ZpbGVzIDwtIGRpcl9scygiZGF0YS9uZ3NhZG1peF9hbGwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlY3Vyc2UgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGdsb2IgPSAiKi5xb3B0X3dpdGhfc2FtcGxlX25hbWVzIikKCm5nc0FkbWl4X3RpYiA8LSBsYXBwbHkobmdzYWRtaXhfZmlsZXMsIGZ1bmN0aW9uKHgpIHsKICByZWFkLnRhYmxlKHgsIAogICAgICAgICAgICAgaGVhZGVyID0gVFJVRSkgJT4lCiAgICBwaXZvdF9sb25nZXIoY29scyA9IC1zYW1wbGUsIAogICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlF2YWwiLCAKICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICAgIG11dGF0ZShwYXRoID0geCwgCiAgICAgICAgICAgLmJlZm9yZSA9IHNhbXBsZSkKfSkgJT4lCiAgYmluZF9yb3dzKCkgJT4lCiAgZmlsdGVyKCFpcy5uYSh2YWx1ZSkpICU+JQogIG11dGF0ZShRdmFsID0gc3RyX3JlcGxhY2UoUXZhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiWCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlEiKSkgJT4lCiAgZXh0cmFjdChwYXRoLCAKICAgICAgICAgIGludG8gPSBjKCJLIiwgCiAgICAgICAgICAgICAgICAgICAicmVwIiksIAogICAgICAgICAgcmVnZXggPSAiLipLXyhbMC05XSspX3JlcF8oWzAtOV0rKS8uKiQiLCAKICAgICAgICAgIGNvbnZlcnQgPSBUUlVFKSAlPiUKICBpbm5lcl9qb2luKC4sIAogICAgICAgICAgICAgbWV0YWRhdGEsIAogICAgICAgICAgICAgYnkgPSBjKCJzYW1wbGUiID0gIk5NRlNfRE5BX0lEIiksIAogICAgICAgICAgICAgcmVsYXRpb25zaGlwID0gIm1hbnktdG8tbWFueSIpICU+JQogIG11dGF0ZShnZmFjdCA9IGZhY3Rvcihncm91cGluZ192MywgCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGdvcmQpLCAKICAgICAgICAgd2ZhY3QgPSBmYWN0b3IoV0FURVJfTkFNRSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHdvcmQpKSAlPiUKICBhcnJhbmdlKGdmYWN0LCB3ZmFjdCkKYGBgCgpgYGB7ciBhbGxfS3N9CmdncGxvdChuZ3NBZG1peF90aWIpICsKICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBmYWN0b3IobmV3bmFtZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG5vcmQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB2YWx1ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gUXZhbCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBxY29sb3JzKSArIAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSA4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuNSkpICsKICBmYWNldF9ncmlkKHJlcCB+IEspICsKICBsYWJzKHggPSAiIiwgCiAgICAgICB5ID0gIlEgdmFsdWUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcG9wX2xhYmVscyRsaW5leCwgCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsIAogICAgICAgICAgICAgY29sb3IgPSAiZ3JheTI1IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGdyb3VwX2xhYmVscyRsaW5leCkKYGBgCgpgYGB7ciBzdWJzZXR9CksyIDwtIG5nc0FkbWl4X3RpYiAlPiUKICBmaWx0ZXIoSyA9PSAyKQoKSzMgPC0gbmdzQWRtaXhfdGliICU+JQogIGZpbHRlcihLID09IDMpCgpLNCA8LSBuZ3NBZG1peF90aWIgJT4lCiAgZmlsdGVyKEsgPT0gNCkKCks1IDwtIG5nc0FkbWl4X3RpYiAlPiUKICBmaWx0ZXIoSyA9PSA1KQoKSzYgPC0gbmdzQWRtaXhfdGliICU+JQogIGZpbHRlcihLID09IDYpCgpLNyA8LSBuZ3NBZG1peF90aWIgJT4lCiAgZmlsdGVyKEsgPT0gNykKCks4IDwtIG5nc0FkbWl4X3RpYiAlPiUKICBmaWx0ZXIoSyA9PSA4KQoKSzkgPC0gbmdzQWRtaXhfdGliICU+JQogIGZpbHRlcihLID09IDkpCgpLMTAgPC0gbmdzQWRtaXhfdGliICU+JQogIGZpbHRlcihLID09IDEwKQpgYGAKCgpgYGB7ciBLMn0KZ2dwbG90KEsyKSArCiAgZ2VvbV9jb2wobWFwcGluZyA9IGFlcyh4ID0gZmFjdG9yKG5ld25hbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBub3JkKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gdmFsdWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IFF2YWwpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcWNvbG9ycykgKyAKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gOCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAwLjUpKSArCiAgZmFjZXRfZ3JpZChyZXAgfiBLKSArCiAgbGFicyh4ID0gIiIsIAogICAgICAgeSA9ICJRIHZhbHVlIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHBvcF9sYWJlbHMkbGluZXgsIAogICAgICAgICAgICAgbGluZXR5cGUgPSAyLCAKICAgICAgICAgICAgIGNvbG9yID0gImdyYXkyNSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBncm91cF9sYWJlbHMkbGluZXgpCmBgYAoKSW4gdGhlIGFkbWl4dHVyZSBzY2VuYXJpbyBvZiAyIHNvdXJjZSBwb3B1bGF0aW9ucywgdGhlIHNhbXBsZXMgc3BsaXQgaW50byB0aGUgdHdvIHNwZWNpZXMgb2YgYmx1ZWJhY2sgKGxlZnQpIGFuZCBhbGV3aWZlIChyaWdodCkuCgpgYGB7ciBLM30KZ2dwbG90KEszKSArCiAgZ2VvbV9jb2wobWFwcGluZyA9IGFlcyh4ID0gZmFjdG9yKG5ld25hbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBub3JkKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gdmFsdWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IFF2YWwpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcWNvbG9ycykgKyAKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gOCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAwLjUpKSArCiAgZmFjZXRfZ3JpZChyZXAgfiBLKSArCiAgbGFicyh4ID0gIiIsIAogICAgICAgeSA9ICJRIHZhbHVlIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHBvcF9sYWJlbHMkbGluZXgsIAogICAgICAgICAgICAgbGluZXR5cGUgPSAyLCAKICAgICAgICAgICAgIGNvbG9yID0gImdyYXkyNSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBncm91cF9sYWJlbHMkbGluZXgpCmBgYAoKSW4gdGhlIGFkbWl4dHVyZSBzY2VuYXJpbyBvZiAzIHNvdXJjZSBwb3B1bGF0aW9ucywgdGhlIEdyZWF0IGFuZCBGaW5nZXIgTGFrZXMgc2FtcGxlcyBwdWxsIG91dCBpbnRvIHRoZWlyIG93biBncm91cC4KCmBgYHtyIEs0fQpnZ3Bsb3QoSzQpICsKICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBmYWN0b3IobmV3bmFtZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG5vcmQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB2YWx1ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gUXZhbCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBxY29sb3JzKSArIAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSA4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuNSkpICsKICBmYWNldF9ncmlkKHJlcCB+IEspICsKICBsYWJzKHggPSAiIiwgCiAgICAgICB5ID0gIlEgdmFsdWUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcG9wX2xhYmVscyRsaW5leCwgCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsIAogICAgICAgICAgICAgY29sb3IgPSAiZ3JheTI1IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGdyb3VwX2xhYmVscyRsaW5leCkKYGBgCgpJbiB0aGUgYWRtaXh0dXJlIHNjZW5hcmlvIG9mIGZvdXIgc291cmNlIHBvcHVsYXRpb25zLCB3ZSBzZWUgdGhlIHRoZSBSb2Fub2tlIFJpdmVyLCBFYXN0IEdyYW5kIExha2UsIGFuZCBMYWtlIENoYW1wbGFpbiBzYW1wbGVzIHB1bGwgb3V0IGludG8gdGhlaXIgb3duIGdyb3VwLiAKCmBgYHtyIEs1fQpnZ3Bsb3QoSzUpICsKICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBmYWN0b3IobmV3bmFtZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG5vcmQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB2YWx1ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gUXZhbCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBxY29sb3JzKSArIAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSA4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuNSkpICsKICBmYWNldF9ncmlkKHJlcCB+IEspICsKICBsYWJzKHggPSAiIiwgCiAgICAgICB5ID0gIlEgdmFsdWUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcG9wX2xhYmVscyRsaW5leCwgCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsIAogICAgICAgICAgICAgY29sb3IgPSAiZ3JheTI1IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGdyb3VwX2xhYmVscyRsaW5leCkKYGBgCgpJbiB0aGUgbW9zdCBhZG1peHR1cmUgc2NlbmFyaW9zIG9mIGZpdmUgc291cmNlIHBvcHVsYXRpb25zLCB3ZSBiZWdpbiB0byBzZWUgR3JlYXQgYW5kIEZpbmdlciBMYWtlcyBmb3JtIGEgbm9uc3BlY2lmaWMgbW9zYWljIGV4Y2VwdCBmb3IgaW4gdGhlIHRoaXJkIHJlcGV0aXRpb24gaW4gd2hpY2ggdGhlIENvbm5lY3RpY3V0IExha2VzIHNhbXBsZXMgYnJlYWsgb3V0IGludG8gdGhlaXIgb3duIGdyb3VwLgoKYGBge3IgSzZ9CmdncGxvdChLNikgKwogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoeCA9IGZhY3RvcihuZXduYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbm9yZCksIAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHZhbHVlLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBRdmFsKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHFjb2xvcnMpICsgCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41KSkgKwogIGZhY2V0X2dyaWQocmVwIH4gSykgKwogIGxhYnMoeCA9ICIiLCAKICAgICAgIHkgPSAiUSB2YWx1ZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBwb3BfbGFiZWxzJGxpbmV4LCAKICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwgCiAgICAgICAgICAgICBjb2xvciA9ICJncmF5MjUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZ3JvdXBfbGFiZWxzJGxpbmV4KQpgYGAKCkluIHRoZSBhbiBhZG1peHR1cmUgc2NlbmFyaW8gb2Ygc2l4IHNvdXJjZSBwb3B1bGF0aW9ucywgd2Ugc2VlIHRoZSBDb25uZWN0aWN1dCBMYWtlcyBzYW1wbGVzIGJyZWFrIG91dCBhbmQgdGhlIHNhbWUgcmFuZG9tIG1vc2FpYyBpbiB0aGUgR3JlYXQgYW5kIEZpbmdlciBMYWtlcyBzYW1wbGVzLCBleGNlcHQgZm9yIGluIHRoZSB0aGlyZCByZXBldGl0aW9uIHdoZXJlIG9ubHkgUGF0dGFnYW5zZXR0IGFuZCBSb2dlcnMgTGFrZXMgc2VwYXJhdGUgb3V0IGludG8gdGhlaXIgb3duIHNvdXJjZSBwb3B1bGF0aW9uLgoKYGBge3IgSzd9CmdncGxvdChLNykgKwogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoeCA9IGZhY3RvcihuZXduYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbm9yZCksIAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHZhbHVlLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBRdmFsKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHFjb2xvcnMpICsgCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41KSkgKwogIGZhY2V0X2dyaWQocmVwIH4gSykgKwogIGxhYnMoeCA9ICIiLCAKICAgICAgIHkgPSAiUSB2YWx1ZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBwb3BfbGFiZWxzJGxpbmV4LCAKICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwgCiAgICAgICAgICAgICBjb2xvciA9ICJncmF5MjUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZ3JvdXBfbGFiZWxzJGxpbmV4KQpgYGAKCkluIGFuIGFkbWl4dHVyZSBzY2VuYXJpbyBvZiBzZXZlbiBzb3VyY2UgcG9wdWxhdGlvbnMsIHRoZSBhbmFkcm9tb3VzIGFsZXdpZmUgc2hvdyB0aGVpciBvd24gc291cmNlIHBvcHVsYXRpb24uIAoKYGBge3IgSzh9CmdncGxvdChLOCkgKwogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoeCA9IGZhY3RvcihuZXduYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbm9yZCksIAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHZhbHVlLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBRdmFsKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHFjb2xvcnMpICsgCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41KSkgKwogIGZhY2V0X2dyaWQocmVwIH4gSykgKwogIGxhYnMoeCA9ICIiLCAKICAgICAgIHkgPSAiUSB2YWx1ZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBwb3BfbGFiZWxzJGxpbmV4LCAKICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwgCiAgICAgICAgICAgICBjb2xvciA9ICJncmF5MjUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gZ3JvdXBfbGFiZWxzJGxpbmV4KQpgYGAKCkluIGFuIGFkbWl4dHVyZSBzY2VuYXJpbyBvZiBlaWdodCBzb3VyY2UgcG9wdWxhdGlvbnMsIGJsdWViYWNrIHNhbXBsZXMgYmVnaW4gdG8gbW9zYWljIGFzIHdlbGwgYXMgdGhlIGFuYWRyb21vdXMgc2FtcGxlcyB3aXRoIHRoZSBRdW9ubmlwYXVnIExha2Ugc2FtcGxlcyBicmVha2luZyBvdXQgd2l0aCB0aGUgc291cmNlIHBvcHVsYXRpb24gbW9yZSBwcmVzZW50IGluIHRoZSBNaWQtQXRsYW50aWMgbWFuYWdpbmcgdW5pdC4gCgpgYGB7ciBLOX0KZ2dwbG90KEs5KSArCiAgZ2VvbV9jb2wobWFwcGluZyA9IGFlcyh4ID0gZmFjdG9yKG5ld25hbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBub3JkKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gdmFsdWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IFF2YWwpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcWNvbG9ycykgKyAKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gOCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAwLjUpKSArCiAgZmFjZXRfZ3JpZChyZXAgfiBLKSArCiAgbGFicyh4ID0gIiIsIAogICAgICAgeSA9ICJRIHZhbHVlIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHBvcF9sYWJlbHMkbGluZXgsIAogICAgICAgICAgICAgbGluZXR5cGUgPSAyLCAKICAgICAgICAgICAgIGNvbG9yID0gImdyYXkyNSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBncm91cF9sYWJlbHMkbGluZXgpCmBgYAoKSW4gYW4gYWRtaXh0dXJlIHNjZW5hcmlvIG9mIG5pbmUgc291cmNlIHBvcHVsYXRpb25zLCBhbGwgYmx1ZWJhY2sgc2FtcGxlcyBjb21lIGZyb20gdGhlIHNhbWUgc291cmNlIHBvcHVsYXRpb24sIHRocmVlIHNvdXJjZSBwb3B1bGF0aW9ucyBtb3NhaWMgdGhyb3VnaCB0aGUgR3JlYXQgYW5kIEZpbmdlciBMYWtlcywgUm9nZXJzIExha2UgYnJlYWtzIG91dCBpbnRvIHRoZWlyIG93biBzb3VyY2UgcG9wdWxhdGlvbiwgYW5kIHRoZSBhbmFkcm9tb3VzIHNhbXBsZXMgbW9zYWljIGludG8gdHdvIG5vbnNwZWNpZmljIHNvdXJjZSBwb3B1bGF0aW9ucy4gCgpgYGB7ciBLMTB9CmdncGxvdChLMTApICsKICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBmYWN0b3IobmV3bmFtZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG5vcmQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB2YWx1ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gUXZhbCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBxY29sb3JzKSArIAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSA4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuNSkpICsKICBmYWNldF9ncmlkKHJlcCB+IEspICsKICBsYWJzKHggPSAiIiwgCiAgICAgICB5ID0gIlEgdmFsdWUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcG9wX2xhYmVscyRsaW5leCwgCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsIAogICAgICAgICAgICAgY29sb3IgPSAiZ3JheTI1IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGdyb3VwX2xhYmVscyRsaW5leCkKYGBgCgpJbiBhbiBhZG1peHR1cmUgc2NlbmFyaW8gb2YgdGVuIHNvdXJjZSBwb3B1bGF0aW9ucywgMS0yIExha2UgQ2hhbXBsYWluIHNhbXBsZXMgYnJlYWsgb3V0IHdpdGggUm9hbm9rZSBSaXZlciBzYW1wbGVzLCB3aXRoIGFsbCBvdGhlciBMYWtlIENoYW1wbGFpbiBhbmQgRWFzdCBHcmFuZCBMYWtlIHNhbXBsZXMgaW4gdGhlaXIgb3duIHNvdXJjZSBwb3B1bGF0aW9uLiBQYXR0YWdhbnNldHQgTGFrZSBicmVha3Mgb3V0IGZyb20gdGhlIG90aGVyIENvbm5lY3RpY3V0IExha2VzIHNhbXBsZXMuCg==